/***************************************************************************
 *   Copyright (C) 2011  by TinySofts                                      *
 *   tinysofts@gmail.com                                                   *
 *   All Rights Reserved.                                                  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   Refer to http://code.google.com/p/tinydict/                           *
 ***************************************************************************/

/*
    UI & func of TinyDict
    Status:Open;ReleaseReady;M
*/

#include <QtSql/QSqlError>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QFile>

#include "mainwindow.h"
#include "aboutdialog.h"
#include "dictinfo.h"

#define TINY_DICT_VER "1.00"
#define TINY_DICT_NAME "Tiny Dict"

/*Functions defined at func.cpp*/
int initTinyDictTables(QString & info );
int initDictInfo(QString & info );
int initTinyDictConfig(QString & info );
int initTinyDictWords(QString & info );
int initBabylonTable(QString &info);
int delBabylonDict(int dictseq);
QByteArray getBabylonDef(int dictseq, QString word);
int ExtractBabylonDict(int dictseq, BabylonDict & b);
int add2TinyDictDB(QString w, QString e);
int genTinyDictDB(QString path, QString filename);

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{
    _seq = 0;
    _lastseq = -1;
    _dicttype= -1;
    tdict=NULL;
    currDict=NULL;
    mainWidget = new QWidget(this);

    createUi();
    createSystray();

    this->setCentralWidget(mainWidget);

    /*
    connect(inputWord,SIGNAL(textChanged(const QString &)), this,
            SLOT(interpretationTextChanged(const QString &)));
    //*/
    connect(inputWord,SIGNAL(textChanged(const QString &)), this,
            SLOT(interTextChanged(const QString &)));

    bool ret = loadAppDB();
    if(!ret)
    {
        QMessageBox::critical(this, tr("Error"),tr("Load AppDB Error"));
        qApp->quit();
    }

    /*install eventHandler*/
    dictList->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(dictList,SIGNAL(customContextMenuRequested(const QPoint&)),
                this, SLOT(showContextMenu(const QPoint&)));
    dictList->viewport()->installEventFilter(this);

}

void MainWindow::createUi()
{
    createMenuBar();
    createComponent();
    mainLayout = new QVBoxLayout(mainWidget);
    mainWidget->setLayout(mainLayout);
    mainLayout->addWidget(promtLabel);
    QHBoxLayout * headlay = new QHBoxLayout();
    headlay->addWidget(inputWord);
    headlay->addWidget(addNewButton);
    mainLayout->addLayout(headlay);
    QHBoxLayout * hLayout = new QHBoxLayout();
    hLayout->addWidget(dictList);
    hLayout->addWidget(explText);
    mainLayout->addLayout(hLayout);
}

void MainWindow::createComponent()
{
    promtLabel = new QLabel(mainWidget);
    promtLabel->setText(tr("words"));
    inputWord = new QLineEdit(this);
    QFont font;
    font.setFamily(QString::fromUtf8("Times New Roman"));
    font.setPointSize(12);
    promtLabel->setFont(font);
    inputWord->setFont(font);
    dictList = new QListWidget(this);
    dictList->setMaximumWidth(150);
    dictList->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Preferred);
    explText = new QTextEdit(this);
    
    font.setFamily(QString::fromUtf8("Courier New"));
    
    font.setPointSize(12);
    explText->setFont(font);
    addNewButton = new QPushButton(tr("Add to New Word"),this);
    addNewButton->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Preferred);
    addNewButton->setMaximumWidth(80);
    addNewButton->setMaximumHeight(40);
    connect(addNewButton,SIGNAL(clicked()),this,SLOT(add2NewWord()));
}

void MainWindow::createMenuBar()
{
    menuBar = new QMenuBar(this);

    menuMain = menuBar->addMenu(tr("TinyDict"));
    menuQuery = menuBar->addMenu(tr("Query"));
    menuAdmin = menuBar->addMenu(tr("Admin"));
    menuTool = menuBar->addMenu(tr("Tool"));
    menuHelp = new QMenu(menuBar);
    menuHelp->setTitle(tr("Help"));
    
    /****** menuMain ******/
    quitAction = new QAction(tr("Quit"),this) ;
    //quitAction->setIcon(QIcon(":/images/quit.png"));
    quitAction->setToolTip(tr("Quit the application"));
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
    QAction * spAction = new QAction(tr("Special"),this) ;
    connect(spAction, SIGNAL(triggered()), this, SLOT(runSpecial()));
    modAction = new QAction(tr("Mode"),this) ;
    modAction->setCheckable(true);
    connect(modAction,SIGNAL(toggled(bool)),this,SLOT(changeMode(bool)));
    //connect(modAction, SIGNAL(triggered()), this, SLOT(notImplement()));
    //menuMain->addAction(spAction);
    menuMain->addAction(modAction);
    menuMain->addSeparator();
    menuMain->addAction(tr("New Word File"),this,SLOT(setWordFile()));
    menuMain->addSeparator();
    menuMain->addAction(quitAction);
    
    /***** menuQuery  *******/
    batchAction = new QAction(tr("BatchQuery"),this);
    connect(batchAction,SIGNAL(triggered()),this,SLOT(batchClicked()));
    menuQuery->addAction(batchAction);
    
    /****** menuAdmin ******/
    QAction * registerAction = new QAction(tr("Register StarDict"),this);
    connect(registerAction, SIGNAL(triggered()), this, SLOT(regStarDict()));    
    QAction * regBglAction = new QAction(tr("Register BabylonDict"),this);
    connect(regBglAction, SIGNAL(triggered()), this, SLOT(regBabylonDict()));
    QAction * buildBglAction = new QAction(tr("Build BabylonDict"),this);
    connect(buildBglAction, SIGNAL(triggered()), this, SLOT(buildBabylonDict()));
    QAction * manageAction = new QAction(tr("Dict Admin"),this);
    connect(manageAction, SIGNAL(triggered()), this, SLOT(notImplement()));
    menuAdmin->addAction(registerAction);
    menuAdmin->addAction(regBglAction);
    //menuAdmin->addAction(buildBglAction);
    //menuAdmin->addAction(manageAction);
    
    /***** menuTool *********/
    QAction * addWordAction = new QAction(tr("Add to TinyDict..."),this);
    connect(addWordAction, SIGNAL(triggered()), this, SLOT(add2TinyDict()));
    QAction * addNewWordAction = new QAction(tr("Add to New Word..."),this);
    connect(addNewWordAction, SIGNAL(triggered()), this, SLOT(add2NewWord()));
    menuTool->addAction(addWordAction);
    menuTool->addAction(addNewWordAction);

    /***** menuHelp  *******/
    aboutAction= new QAction(tr("About"),this);
    connect(aboutAction, SIGNAL(triggered()), this, SLOT(showAbout()));
    menuHelp->addAction(aboutAction);
    menuBar->addAction(menuHelp->menuAction());
    this->setMenuBar(menuBar);
}

void MainWindow::createSystray()
{
    if (!QSystemTrayIcon::isSystemTrayAvailable())
        return;
    QAction *quitAction = new QAction(tr("&Quit"), this);
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));

    QAction *restoreAction = new QAction(tr("&Restore"), this);
    connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));

    QAction *minimizeAction = new QAction(tr("&Minimize"),this);
    connect(minimizeAction,SIGNAL(triggered()), this, SLOT(hide()));

    QSystemTrayIcon *trayIcon = new QSystemTrayIcon(this);
    QMenu *trayIconMenu = new QMenu(this);
    trayIconMenu->addAction(minimizeAction);
    trayIconMenu->addAction(restoreAction);
    trayIconMenu->addAction(quitAction);
    trayIcon->setContextMenu(trayIconMenu);

    connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this,SLOT(systrayClicked(QSystemTrayIcon::ActivationReason)));
    QIcon icon(":images/dict.png");
    trayIcon->setIcon(icon);
    trayIcon->show();
}

/****SLOTS****/
void MainWindow::batchClicked()
{
    QFileDialog::Options options;
    //options |= QFileDialog::DontUseNativeDialog;
    QString selectedFilter;
    QString fileName = QFileDialog::getOpenFileName(this,
                                tr("Find words text"),
                                ".",
                                tr("All Files (*);;Text Files (*.txt)"),
                                &selectedFilter,
                                options);
    if (!fileName.isEmpty()) {
        QFile input(fileName);
        if(input.exists()) {
            QString outInter = fileName+"."+QDate::currentDate().toString()+".txt";
            QFile output(outInter);
            output.open(QIODevice::ReadWrite);
            input.open(QIODevice::ReadOnly);
            QByteArray line=input.readLine();
            while(line.size()!=0) {
                /*line not trimmed*/
                QString w(line);
                QByteArray exp;
                if(_seq==0) /*default dict*/
                {
                    if(_mode==1)
                        exp = this->lookUpDict2(w);
                    else
                        exp = this->lookUpDict(w);
                }
                else  if(_dicttype==2) /*It is an Extraced BabylonDict*/
                {
                    exp = getBabylonDef(_seq,w);
                }
                else {
                    if(currDict==NULL) /*set default, not clicked*/
                    {
                        if(_dicttype==0) /*It is a StarDict*/
                        {
                            currDict=new TDict;
                        }
                        else if(_dicttype==1) /*It is a BabylonDict*/
                        {
                            currDict=new BabylonDict;
                        }
                        if(currDict==NULL)
                        {
                            explText->setText("ErrorInfo: currDict==NULL");
                            return;
                        }
                        bool ret = currDict->setPath(_path,_filename);
                        if(ret)
                        {
                            ret=currDict->init();
                            if(!ret)
                            {
                                explText->setText(_filename);
                            }
                        }
                        else
                        {
                            explText->setText("ErrorInfo:setPath"+_filename);
                        }
                    }
                    if(_mode==1)
                        exp = currDict->lookUpDict2(w);
                    else
                        exp = currDict->lookUpDict(w);
                }
                output.write(line);
                output.write(exp);
                output.write("\r\n*****************\r\n");
                line=input.readLine();
            }
            QFileInfo info(input);
            QMessageBox::about(this,tr("Complete"),tr("Query Complete"));
            QDesktopServices::openUrl(QUrl("file:///"+info.absolutePath()));
        }
    }
}

void MainWindow::showContextMenu(const QPoint &)
{
    QListWidgetItem *li = dictList->selectedItems().at(0);
    if(li) {
        QMenu* popMenu = new QMenu(this);
        QAction * infoAction = new QAction(tr("&Property"), popMenu);
        connect(infoAction, SIGNAL(triggered()), this, SLOT(showDictInfo()));
        QAction * setDefaultAction = new QAction(tr("&Set Default"), popMenu);
        connect(setDefaultAction, SIGNAL(triggered()), this, SLOT(setDefaultDict()));
        popMenu->addAction(infoAction);
        popMenu->addAction(setDefaultAction);
        int selected = li->data(Qt::UserRole).toInt();
        if(selected !=0) {
            QAction * delAction = new QAction(tr("&Delete"), popMenu);
            connect(delAction, SIGNAL(triggered()), this, SLOT(unregisterDict()));
            popMenu->addAction(delAction);
        }
        popMenu->exec(QCursor::pos());
    }
}

void MainWindow::setDefaultDict()
{
    int ret;
    ret=setConfig("defaultdict",QString::number(_seq));
    ret=setConfig("defaultdicttype",QString::number(_dicttype));
    ret=setConfig("_path",_path);
    ret=setConfig("_filename",_filename);
}

void MainWindow::showDictInfo()
{
    QListWidgetItem *li = dictList->selectedItems().at(0);
    if(li)
    {
        int selected = li->data(Qt::UserRole).toInt();
        if( selected == 0 )
        {
            QSqlQuery query;
            query.prepare("SELECT COUNT(*) FROM words");
            bool res = query.exec();
            if(!res)
            {
                QMessageBox::about(this, tr("Query DB Error"),
                                   query.lastError().text());
            }
            if(query.next())
            {
                int wordcount = query.value(0).toInt();
                DictInfo dictInfo;
                dictInfo.setName(TINY_DICT_NAME);
                dictInfo.setWordCount(wordcount);
                dictInfo.setVersion(TINY_DICT_VER);
                dictInfo.exec();
            }
        }
        else
        {
            /*query from database*/
            QSqlQuery query;
            query.prepare("SELECT dictname,wordcount,version FROM dictinfo WHERE seq=:id");
            query.bindValue(":id", selected);
            bool res = query.exec();
            if(!res)
            {
                QMessageBox::about(this, tr("Query DB Error"),
                                   query.lastError().text());
            }
            if(query.next())
            {
                QString dictname = query.value(0).toString();
                int wordcount = query.value(1).toInt();
                QString ver = query.value(2).toString();
                DictInfo dictInfo;
                dictInfo.setName(dictname.trimmed());
                dictInfo.setWordCount(wordcount);
                dictInfo.setVersion(ver);
                dictInfo.exec();
            }
        }
    }
}

bool MainWindow::eventFilter(QObject * object, QEvent *event)
{
    if (object==dictList->viewport())
    {
        if( event->type() == QEvent::MouseButtonPress)
        {
            
            QMouseEvent *pMouseEvent = static_cast<QMouseEvent *>(event);
            if(pMouseEvent->button()==Qt::LeftButton) 
            {
                QListWidgetItem * li = dictList->itemAt(pMouseEvent->x(),
                                                        pMouseEvent->y());
                if(li)
                {
                    li->setSelected(true);
                    /*current seq*/
                    if(_seq != li->data(Qt::UserRole).toInt()) {
                        _seq = li->data(Qt::UserRole).toInt();
                        _path = li->data(Qt::UserRole+1).toString();
                        _filename = li->data(Qt::UserRole+2).toString();
                        _dicttype = li->data(Qt::UserRole+3).toInt();
                        /*SHOULD USE SIGNAL HERE*/
                        //interpretationTextChanged(inputWord->text());
                        interTextChanged(inputWord->text());
                    }
                    return true;
                }
            }
        }
    }
    return QWidget::eventFilter(object, event);
}

void MainWindow::unregisterDict()
{
    QListWidgetItem *li = dictList->selectedItems().at(0);
    if(li)
    {
        int selected = li->data(Qt::UserRole).toInt();
        int t=li->data(Qt::UserRole+3).toInt();
        if(selected ==0)
        {
            return;
        }
        QMessageBox msgbox;
        msgbox.setText(tr("Are you sure?"));
        msgbox.setStandardButtons(QMessageBox::Ok |
                                  QMessageBox::Cancel);
        int ret = msgbox.exec();

        if(ret==QMessageBox::Cancel)
        {
            return;
        }

        if(_seq == selected )
        {
            _seq = 0;
            interpretationTextChanged(inputWord->text());
            dictList->item(0)->setSelected(true);
        }

        /*delete from database*/
        QSqlQuery query;
        query.prepare("DELETE FROM dictinfo WHERE seq=:id");
        query.bindValue(":id", selected);
        bool res = query.exec();
        if(!res)
        {
            QMessageBox::about(this, tr("DB ERROR"),query.lastError().text());
        }
        if(t==2)
        {
            QString info;
            int r=delBabylonDict(selected);
            if(r<0) {
                QMessageBox::critical(this,QString::number(r),info);
            }
        }
        delete li;
    }
}

/*Register StarDict*/
void MainWindow::regStarDict()
{
    QFileDialog::Options options = QFileDialog::DontResolveSymlinks
                                   | QFileDialog::ShowDirsOnly;
    //options |= QFileDialog::DontUseNativeDialog;
    QString directory = QFileDialog::getExistingDirectory(this,
                                tr("Dictionary Dir"),
                                tr(""),
                                options);
    if (!directory.isEmpty())
    {
        QDir d(directory,"*.ifo");
        QStringList sl=d.entryList();
        if(sl.size()!=1) {
            QMessageBox::about(this,tr("Can not register stardict"),
                               tr("*.ifo Number:")+QString::number(sl.size()));
            return;
        }
        QString infoname = sl[0];
        QString filename = infoname.left(infoname.size()-4);
        /*check*/
        QFile dzfile(directory+QDir::separator()+filename+".dict.dz");
        if(!dzfile.exists())
        {
            QMessageBox::critical(this, tr("Can not register stardict"),
                                  tr(".dict.dz not exists"));
            return;
        }
        QFile idxfile(directory+QDir::separator()+filename+".idx");
        if(!idxfile.exists())
        {
            QMessageBox::critical(this, tr("Can not register stardict"),
                                  tr(".idx not exists"));
            return;
        }
        /*get dictname */
        QFile infofile(directory+QDir::separator()+filename+".ifo");
        infofile.open(QFile::ReadOnly);
        QString dictname("No Named Dict");
        char line[128];
        int len = infofile.readLine(line,128);
        int wordcount = -1;
        QString ver;
        while(len>0){
            QString l(line);
            if(l.startsWith("bookname=")){
                dictname = l.right(l.size()-9);
            }
            if(l.startsWith("wordcount=")) {
                wordcount = l.right(l.size()-10).trimmed().toInt();
            }
            if(l.startsWith("version="))
            {
                ver=l.right(l.size()-8).trimmed();
            }
            len = infofile.readLine(line,128);
        }
        dictname=dictname.trimmed();
        QMessageBox::about(this,tr("Info "),
                           tr("Register a dictionary named: ")+dictname);
        QSqlQuery query;
        query.prepare("SELECT MAX(seq) FROM dictinfo");
        bool res = query.exec();
        if(!res)
        {
            QMessageBox::critical(this, tr("get dictseq"),
                                  query.lastError().text());
            return;
        }
        query.next();
        int dictseq = query.value(0).toInt();
        query.prepare("INSERT INTO dictinfo VALUES"
                      "(:seq, :type, :dictname,:dictpath, "
                      ":filename,:wordcount,:version)");
        query.bindValue(":seq",dictseq+1);
        query.bindValue(":type",0);
        query.bindValue(":dictname",dictname);
        query.bindValue(":dictpath",directory);
        query.bindValue(":filename",filename);
        query.bindValue(":wordcount",wordcount);
        query.bindValue(":version",ver);
        res = query.exec();
        if(!res)
        {
            QMessageBox::critical(this, tr("register Dict"),
                                  query.lastError().text());
        }

        /*Update dictList*/
        QListWidgetItem * n = new QListWidgetItem(dictname);
        n->setData(Qt::UserRole,dictseq+1);
        n->setData(Qt::UserRole+1,directory);
        n->setData(Qt::UserRole+2,filename);
        n->setData(Qt::UserRole+3,0);
        dictList->addItem(n);

    }
}

/*Register Babylon Dict*/
void MainWindow::regBabylonDict()
{
    QFileDialog::Options options = QFileDialog::DontResolveSymlinks;
    QString selectedFilter;
    //options |= QFileDialog::DontUseNativeDialog;
    QString babylonFile = QFileDialog::getOpenFileName(this,
                                                     tr("New Babylon Dict"),
                                                     ".",
                                                     "BGL (*.bgl)",
                                                     &selectedFilter,
                                                     options);
    if (!babylonFile.isEmpty())
    {
        /*check it*/
        QByteArray t;
        t.append(babylonFile);
        BabylonDict b(t.data());
        int s = b.open();
        if(s<0) {
            QMessageBox::critical(this,tr("Open Babylon Dict Error"),
                                  babylonErrorMsg[-s]);
            return;
        }
        b.read();
        QString title(b.title().c_str());
        int wordcount=b.numEntries();
        QSqlQuery query;
        query.prepare("SELECT MAX(seq) FROM dictinfo");
        bool res = query.exec();
        if(!res)
        {
            QMessageBox::critical(this, tr("get dictseq"),
                                  query.lastError().text());
            return;
        }
        query.next();
        int dictseq = query.value(0).toInt();
        query.prepare("INSERT INTO dictinfo VALUES"
                      "(:seq, :typ, :dictname,:dictpath, :filename,"
                       ":wordcount,:version)");
        query.bindValue(":seq",dictseq+1);
        query.bindValue(":type",1);
        query.bindValue(":dictname",title);
        query.bindValue(":dictpath","");
        query.bindValue(":filename",babylonFile);
        query.bindValue(":wordcount",wordcount);
        query.bindValue(":version","");
        res = query.exec();
        if(!res)
        {
            QMessageBox::critical(this, tr("REG Babylon Dict Error"),
                                  query.lastError().text());
        }

        /*Update dictList*/
        QListWidgetItem * n = new QListWidgetItem(title);
        n->setData(Qt::UserRole,dictseq+1);
        n->setData(Qt::UserRole+1,"");
        n->setData(Qt::UserRole+2,babylonFile);
        n->setData(Qt::UserRole+3,1);
        dictList->addItem(n);

    }
}

/*Build Babylon Dict*/
void MainWindow::buildBabylonDict()
{
    QFileDialog::Options options = QFileDialog::DontResolveSymlinks;
    QString selectedFilter;
    //options |= QFileDialog::DontUseNativeDialog;
    QString babylonFile = QFileDialog::getOpenFileName(this,
                                                     tr("New Babylon Dict"),
                                                     ".",
                                                     "BGL (*.bgl)",
                                                     &selectedFilter,
                                                     options);
    if (!babylonFile.isEmpty())
    {
        /*check it*/
        QByteArray t;
        t.append(babylonFile);
        BabylonDict b(t.data());
        int s = b.open();
        if(s<0) {
            QMessageBox::critical(this,tr("Open Babylon Dict Error"),
                                  babylonErrorMsg[-s]);
            return;
        }
        b.read();
        QString title(b.title().c_str());
        int wordcount=b.numEntries();
        QSqlQuery query;
        query.prepare("SELECT MAX(seq) FROM dictinfo");
        bool res = query.exec();
        if(!res)
        {
            QMessageBox::critical(this, tr("get dictseq"),
                                  query.lastError().text());
            return;
        }
        query.next();
        int dictseq = query.value(0).toInt();
        wordcount = ExtractBabylonDict(dictseq+1,b);
        query.prepare("INSERT INTO dictinfo VALUES"
                      "(:seq, :typ, :dictname,:dictpath, :filename,"
                       ":wordcount,:version)");
        query.bindValue(":seq",dictseq+1);
        query.bindValue(":type",2);
        query.bindValue(":dictname",title);
        query.bindValue(":dictpath","");
        query.bindValue(":filename",babylonFile);
        query.bindValue(":wordcount",wordcount);
        query.bindValue(":version","");
        res = query.exec();
        if(!res)
        {
            QMessageBox::critical(this, tr("REG Babylon Dict Error"),
                                  query.lastError().text());
        }
        /*Update dictList*/
        QListWidgetItem * n = new QListWidgetItem(title);
        n->setData(Qt::UserRole,dictseq+1);
        n->setData(Qt::UserRole+1,"");
        n->setData(Qt::UserRole+2,babylonFile);
        n->setData(Qt::UserRole+3,2);
        dictList->addItem(n);

    }
}

void MainWindow::add2TinyDict()
{
    int r=add2TinyDictDB(inputWord->text(),explText->toPlainText());
    //
    if(r>=0) 
    {
        QMessageBox::about(this,tr("Add OK"),tr("Add to TinyDict successfully"));
    }
    else
    {
        QMessageBox::about(this,tr("Add Error"),
                           tr("Add to TinyDict failed. reason: ")+QString::number(r));
    }
}


void MainWindow::interpretationTextChanged(const QString &w)
{
    explText->setText("querying...");
    bool ret = true;
    if(_seq==0) {
        QString e;
        if(_mode==1)
            e= this->lookUpDict2(w);
        else
            e= this->lookUpDict(w);
        explText->setText(e);
    }
    else {
        if(_seq != _lastseq) {
            if(_dicttype==0) /*It is a StarDict*/
            {
                if(tdict) delete tdict;
                tdict = new TDict();
                if(tdict) {
                  ret = tdict->setPath(_path,_filename);
                  if(!ret) {
                      QMessageBox::critical(this,"",tr("Init StarDict Error"));
                  }
                }
            }
            else if(_dicttype==1) /*It is a BabylonDict*/
            {
                if(bdict) delete bdict;
                QByteArray t;
                t.append(_filename);
                bdict = new BabylonDict(t.data());
                bool status = false;
                if(bdict) {
                    status = bdict->open();
                }
                if(!status) {
                    QMessageBox::critical(this,"",tr("open BabylonDict Error"));
                }
            }
        }
        if(_dicttype==0) /*It is a StarDict*/
        {
            QString e;
            if(_mode==1)
                e= tdict->lookUpDict2(w);
            else
                e= tdict->lookUpDict(w);
            explText->setText(e);
        }
        else if(_dicttype==1) /*It is a BabylonDict*/
        {
            /*How to display should be improved*/
            explText->setHtml(bdict->lookUp(w));
        }
        else if(_dicttype==2) /*It is an Extraced BabylonDict*/
        {
            QByteArray e=getBabylonDef(_seq,w);
            /*How to display should be improved*/
            explText->setHtml(e);
        }
    }
    _lastseq=_seq;
}

void MainWindow::interTextChanged(const QString &w)
{
    explText->setText("querying...");

    if(_seq==0) /*default dict*/
    {
        QString e;
        if(_mode==1)
            e= this->lookUpDict2(w);
        else
            e= this->lookUpDict(w);
        explText->setText(e);
    }
    else  if(_dicttype==2) /*It is an Extraced BabylonDict*/
    {
        QByteArray e=getBabylonDef(_seq,w);
        /*How to display should be improved*/
        explText->setText(e);
        return;
    }
    else {
        if(_seq != _lastseq) {
            if(currDict)
                delete currDict;
            if(_dicttype==0) /*It is a StarDict*/
            {
                currDict=new TDict;
            }
            else if(_dicttype==1) /*It is a BabylonDict*/
            {
                currDict=new BabylonDict;
            }
            if(currDict==NULL)
            {
                explText->setText("ErrorInfo: currDict==NULL");
                return;
            }
            bool ret = currDict->setPath(_path,_filename);
            if(ret)
            {
                ret=currDict->init();
                if(!ret)
                {
                    explText->setText(_filename);
                }
            }
            else
            {
                explText->setText("ErrorInfo:setPath"+_filename);
            }
        }
        QString e;
        if(_mode==1)
            e = QString::fromUtf8(currDict->lookUpDict2(w).data());
        else
            e = QString::fromUtf8(currDict->lookUpDict(w).data());
        explText->setText(e);
    }
    _lastseq = _seq;
}

bool MainWindow::loadAppDB()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("td.db");
    if (!db.open())
    {
        QMessageBox::critical(this, tr("Open AppDB Error"),
                              db.lastError().text());
        qApp->quit();
        return false;
    }
    else
    {
        QString info;
        int ret = 0;
        if (db.tables().indexOf("words") == -1)
        {
            ret = initTinyDictWords(info);
        }
        if (ret>=0 && db.tables().indexOf("dictinfo") == -1)
        {
            ret = initDictInfo(info);
        }
        if(ret>=0 && db.tables().indexOf("config") == -1)
        {
            ret = initTinyDictConfig(info);
        }
        if(ret>=0 && db.tables().indexOf("babylon") == -1)
        {
            ret = initBabylonTable(info);
        }
        if(ret<0)
        {
            QMessageBox::critical(this, QString::number(ret),info);
            return false;
        }
    }

    /* mode */
    _mode = 1;
    QString v = getConfig("mode");
    if(v=="exact") {
        _mode=0;
        modAction->setChecked(true);
    }
    _wordFile = getConfig("newwordfile");
    QString defaultdict = getConfig("defaultdict");
    QString defaultdicttype = getConfig("defaultdicttype");
    if(defaultdict.trimmed().isEmpty() ||
       defaultdicttype.trimmed().isEmpty())
    {
        _seq = 0;
    }
    else
    {
        _seq = defaultdict.toInt();
        _dicttype = defaultdicttype.toInt();
        _path = getConfig("_path");
        _filename = getConfig("_filename");
    }
    
    QListWidgetItem * defItem = new QListWidgetItem("TinyDict");
    defItem->setData(Qt::UserRole,0);/*SeqNum*/
    defItem->setData(Qt::UserRole+1,"");
    defItem->setData(Qt::UserRole+2,"");
    defItem->setData(Qt::UserRole+3,-1);/*DictType*/
    dictList->addItem(defItem);
    if(_seq==0)
        dictList->setCurrentItem(defItem);
    QSqlQuery query;
    query.prepare("SELECT seq,dictname,dictpath,filename,type FROM dictinfo "
                  "WHERE seq>0");
    bool res = query.exec();
    if(!res)
    {
        QMessageBox::critical(this, tr("Load DictInfo"),
                              query.lastError().text());
        return false;
    }
    else{
        while(query.next())
        {
           QString dictname = query.value(1).toString();
           QListWidgetItem * li = new QListWidgetItem(dictname);
           li->setData(Qt::UserRole, query.value(0));
           li->setData(Qt::UserRole+1,query.value(2));
           li->setData(Qt::UserRole+2,query.value(3));
           li->setData(Qt::UserRole+3,query.value(4));
           dictList->addItem(li);
           if(query.value(0).toInt()==_seq)
           {
               li->setSelected(true);
               dictList->setCurrentItem(li);
           }
           
       }
    }
    return true;
}

QByteArray MainWindow::lookUpDict(const QString &word)
{
    QByteArray interpretation("");;
    QString w = word.trimmed();
    if(w=="") {
        return interpretation;
    }
    QSqlQuery query;
    query.prepare("SELECT explanation FROM words WHERE word =:w");
    query.bindValue(":w", w);
    bool res = query.exec();
    if(res)
    {
        res = query.next();
        if(res) {
            QByteArray bytes = query.value(0).toByteArray();
            interpretation = qUncompress(bytes);
        }
        else {
            interpretation.append(word);
        }
    }
    else
    {
        QMessageBox::about(this, tr("DB ERROR"),query.lastError().text());
    }
    
    return interpretation;
}

QByteArray MainWindow::lookUpDict2(const QString &word)
{
    QByteArray interpretation("");;
    QString w = word.trimmed();
    if(w=="") {
        return interpretation;
    }
    QSqlQuery query;
    query.prepare("SELECT explanation,word FROM words "
                  "WHERE word <=:w ORDER BY word DESC");
    query.bindValue(":w", w);
    bool res = query.exec();
    if(res)
    {
        res = query.next();
        if(res) {
            QByteArray bytes = query.value(0).toByteArray();
            interpretation.append(query.value(1).toString());
            interpretation.append("\r\n");
            interpretation.append(qUncompress(bytes));
            return interpretation;
        }
        else {
            interpretation.append(word);
        }
    }
    else
    {
        QMessageBox::about(this, tr("DB ERROR"),query.lastError().text());
    }

    return interpretation;
}


void MainWindow::changeMode(bool m)
{
    //m=modAction->isChecked();
    int ret;
    if(m) {
        _mode=0;
        ret=setConfig("mode","exact");
    }
    else {
        _mode=1;
        ret=setConfig("mode","");
    }
    //QMessageBox::about(this,"",QString::number(ret));
}

QString MainWindow::getConfig(QString key)
{
    QSqlQuery query;
    query.prepare("SELECT v FROM config WHERE k =:key");
    query.bindValue(":key", key);
    bool res = query.exec();
    if(res)
    {
        res = query.next();
        if(res) {
            return query.value(0).toString();
        }
    }
    return "";
}

int MainWindow::setConfig(QString key, QString value)
{
    QSqlQuery query;
    query.prepare("INSERT INTO config VALUES (:k, :v)");
    query.bindValue(":k", key);
    query.bindValue(":v",value);
    bool res = query.exec();
    if(!res)
    {
        query.prepare("UPDATE config SET v =:v "
                      "WHERE k =:k");
        query.bindValue(":k", key);
        query.bindValue(":v",value);
        res = query.exec();
        if(res)
        { return 0;}
        else
        {
          QMessageBox::about(this, QString::number(-2),
                            query.lastError().text());
          return -2;
        }
    }
    else
    {
        return 1;
    }
    return 0;
}

void MainWindow::showAbout()
{
    AboutDialog about;
    about.exec();
}

void MainWindow::setWordFile()
{
    QString selectedFilter;
    QFileDialog::Options options;
    QString wordfile;
    wordfile = QFileDialog::getSaveFileName(this,
                                tr("New Word File"),
                                ".",
                                tr("All Files (*)"),
                                &selectedFilter,
                                options);
    if(!wordfile.isEmpty())
    {
        _wordFile=wordfile;
        setConfig("newwordfile",_wordFile);
    }
}

void MainWindow::add2NewWord()
{
    if(!_wordFile.isEmpty() && !inputWord->text().trimmed().isEmpty())
    {
        QFile o(_wordFile);
        o.open(QFile::Append);
        QByteArray w;
        w.append(inputWord->text().trimmed()+"\r\n");
        o.write(w);
        o.close();
    }
}

void MainWindow::systrayClicked(QSystemTrayIcon::ActivationReason reason)
{
    if(reason == QSystemTrayIcon::DoubleClick)
        showNormal();
}

/*Command Line Functions*/
void MainWindow::initConfig()
{
    QString info;
    initTinyDictConfig(info);
}

void MainWindow::initBabylonDicts()
{
    QString info;
    int r=initBabylonTable(info);
    if(r<0) {
        QMessageBox::critical(this,QString::number(r),info);
    }
}

void MainWindow::clearDictInfo()
{
    QString info;
    int ret = initDictInfo(info);
    if(ret<0) {
        QMessageBox::critical(this,QString::number(ret),info);
    }
}


/************/
void MainWindow::notImplement()
{
    QMessageBox::about(this,tr("Not Implement"),tr("This featrue has not implemented yet"));

    /*DEBUG CODE*/
}

void MainWindow::runSpecial()
{
    clearDictInfo();
    QString path = "";
    QString filename = "";
    //QMessageBox::about(this,"WordNum","Starting");
    //ExtractStarDict p(path,filename);
    //p.start();
    //int res = genTinyDictDB(path, filename);
    //QMessageBox::about(this,"WordNum","Started");
    //QMessageBox::about(this,"WordNum",QString::number(res));
}
